package ch.bfh.fbi.mobicomp.zap08;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.os.PowerManager;
import android.util.Log;
import ch.simplix.android.speech.string.FrenchString;
import ch.simplix.android.speech.string.GermanString;
import ch.simplix.android.speech.string.UKString;

/**
 * Zap07 does work fine, even if the display is switched off. However, it keeps the device awake all the time. That will drain
 * the battery during sleep Due to the wake-lock.
 * 
 * Zap08 uses the alarmManager, and requests to be notified. This way, the device can go to deep-sleep during the waiting period. The alarmManager
 * will wake up the device and will notify the service (Broadcastreceiver)
 * 
 * @author SimpliX
 *
 */
public class Zap08Service extends Service {

	private static final String TAG = "Zap08Service";

	private PowerManager.WakeLock wakeLock;
	private AlarmManager am;
	private PendingIntent sender;
	public static final String ACTION_REPEAT = "ch.bfh.fbi.mobicomp.zap08.ACTION_REPEAT";
	private IntentFilter alarmRepeater;
	private AlarmHandler alarmHandler;

	private Intent speechIntent = new Intent(
			"ch.simplix.android.speech.SPEECH_SERVICE");
	private long countdown;

	@Override
	public IBinder onBind(Intent intent) {
		// We do not want to grand explicite access!
		return null;
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		if (intent.getExtras().getBoolean("start")) {
			if (am == null) {
				Log.d(TAG, "destruction initiated...");
				initiateAutoDestruction();
			}
		} else if (intent.getExtras().getBoolean("stop")) {
			Log.d(TAG, "destruction aborted...");
			resetAutoDestruction();

		} else {
			Log.d(TAG, "unknown command.");
		}

		return super.onStartCommand(intent, flags, startId);
	}

	private void resetAutoDestruction() {
		if (countdown == 0)
			return;
		initiateWakeLock();
		countdown = 0;
		unregisterAlarmManager();
		speechIntent.putExtra("Phrase", new UKString(
				"Self destruction sequence aborted."));
		startService(speechIntent);
		speechIntent.putExtra("Phrase", new GermanString(
				"Selbstzerstörungssequenz abgebrochen."));
		startService(speechIntent);
		speechIntent.putExtra("Phrase", new FrenchString(
				"Séquence d'autodestruction avortée."));
		startService(speechIntent);
		removeWakeLock();
	}

	private void initiateAutoDestruction() {
		if (countdown != 0)
			return;
		initiateWakeLock();
		registerAlarmManager();
		countdown = System.currentTimeMillis() + 3 * 60 * 1000;
		speechIntent.putExtra("Phrase", new UKString(
				"Self destruction sequence initiated."));
		startService(speechIntent);
		speechIntent.putExtra("Phrase", new GermanString(
				"Selbstzerstörungs Sequenz eingeleitet."));
		startService(speechIntent);
		speechIntent.putExtra("Phrase", new FrenchString(
				"Séquence d'autodestruction declanchée."));
		startService(speechIntent);
		countDown();
		removeWakeLock();
	}

	private void countDown() {
		initiateWakeLock();
		int timeLeft = (int) ((countdown - System.currentTimeMillis()) / 1000);
		if (timeLeft > 70) {
			setAlarmManagerRepeating(60000);
			minutesCount(timeLeft);
		} else if (timeLeft > 11) {
			setAlarmManagerRepeating(10000);
			secondsBlockCount(timeLeft);
		} else if (timeLeft > 0) {
			setAlarmManagerRepeating(1000);
			secondsCount(timeLeft);
		} else {
			destroy();
		}
		removeWakeLock();
	}

	private void minutesCount(int timeLeft) {
		speechIntent.putExtra("Phrase", new UKString(""
				+ (1 + (timeLeft / (60))) + "Minutes until self destruction"));
		startService(speechIntent);
		speechIntent
				.putExtra("Phrase", new GermanString(""
						+ (1 + (timeLeft / (60)))
						+ "Minuten bis zur Selbstzerstörung"));
		startService(speechIntent);
		speechIntent.putExtra("Phrase", new FrenchString(""
				+ (1 + (timeLeft / (60)))
				+ "minutes jusqu'à ce que l'auto-destruction"));
		startService(speechIntent);
	}

	private void secondsBlockCount(int timeLeft) {
		if (timeLeft % 3 == 0) {
			speechIntent.putExtra("Phrase", new UKString(""
					+ (10 + (timeLeft / 10 * 10))
					+ "Seconds until self destruction"));
		} else if (timeLeft % 3 == 1) {
			speechIntent.putExtra("Phrase", new GermanString(""
					+ (10 + (timeLeft / 10 * 10))
					+ "Sekunden bis zur Selbstzerstörung"));
		} else {
			speechIntent.putExtra("Phrase", new FrenchString(""
					+ (10 + (timeLeft / 10 * 10))
					+ "seconds jusqu'à ce que l'auto-destruction"));
		}
		startService(speechIntent);
	}

	private void secondsCount(int timeLeft) {
		speechIntent.putExtra("Phrase", new UKString("" + (timeLeft)));
		startService(speechIntent);
	}

	private void destroy() {
		countdown = 0;
		unregisterAlarmManager();
		speechIntent.putExtra("Phrase", new UKString("Self destroying now."));
		startService(speechIntent);
	}

	private void initiateWakeLock() {
		if (wakeLock == null) {
			PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
			wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK
					| PowerManager.ON_AFTER_RELEASE, TAG);
			wakeLock.acquire();
		}

	}

	private void removeWakeLock() {
		if (wakeLock != null) {
			wakeLock.release();
			wakeLock = null;
		}
	}

	public void registerAlarmManager() {
		alarmHandler = new AlarmHandler();
		this.am = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
		if (alarmRepeater == null) {
			alarmRepeater = new IntentFilter(ACTION_REPEAT);
			this.registerReceiver(alarmHandler, alarmRepeater);
		}
		Intent intent = new Intent(ACTION_REPEAT);

		// In reality, you would want to have a static variable for the
		// request code instead of 0
		sender = PendingIntent.getBroadcast(this, 0, intent,
				PendingIntent.FLAG_UPDATE_CURRENT);
		Log.d(TAG, "Registered at the AlarmManager");
	}

	public void setAlarmManagerRepeating(long delayInMillis) {
		if (am == null)
			return;

		am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
				+ delayInMillis, delayInMillis, sender);
		Log.d(TAG, "Set the next Alert");
	}

	public void unregisterAlarmManager() {
		if (am == null)
			return;
		Log.d(TAG, "Unregistering at the AlarmManager");
		am.cancel(sender);
		unregisterReceiver(alarmHandler);
		sender = null;
		alarmHandler = null;
		alarmRepeater = null;
		am = null;
	}

	class AlarmHandler extends BroadcastReceiver {
		@Override
		public void onReceive(Context context, Intent intent) {
			Log.d(TAG, "Triggered by AlarmManager");
			countDown();
		}

	}
}
